package middleware

import (
	"fitness/go-admin/internal/model"
	"fitness/go-admin/internal/repository"
	"fitness/go-admin/internal/service"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// OperationLog 操作日志中间件
func OperationLog(userRepo repository.UserRepository, logService service.OperationLogService) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 记录请求开始时间
		startTime := time.Now()

		// 获取用户ID（如果已认证）
		userID, exists := c.Get("userId")
		var username string
		var uid uint

		if exists {
			uid = userID.(uint)
			// 获取用户名
			user, err := userRepo.GetByID(uid)
			if err == nil {
				username = user.Username
			}
		}

		// 继续处理请求
		c.Next()

		// 请求处理完成后记录操作日志
		// 获取响应状态码
		statusCode := c.Writer.Status()

		// 获取请求方法和路径
		method := c.Request.Method
		path := c.Request.URL.Path

		// 获取IP地址
		ip := c.ClientIP()

		// 获取User-Agent
		userAgent := c.GetHeader("User-Agent")

		// 确定操作类型和资源类型
		action, resource := determineActionAndResource(method, path)

		// 创建操作日志记录
		log := &model.OperationLog{
			UserID:    uid,
			Username:  username,
			IP:        ip,
			UserAgent: userAgent,
			Method:    method,
			Path:      path,
			Action:    action,
			Resource:  resource,
			Status:    statusCode,
			Details:   "耗时: " + time.Since(startTime).String(),
			CreatedAt: time.Now(),
		}

		// 异步保存操作日志（避免影响主请求处理）
		go func() {
			// 忽略一些不需要记录的日志路径
			if shouldIgnoreLog(path) {
				return
			}

			// 保存操作日志
			_ = logService.CreateLog(log)
		}()
	}
}

// determineActionAndResource 根据请求方法和路径确定操作类型和资源类型
func determineActionAndResource(method, path string) (action, resource string) {
	// 默认值
	action = method
	resource = "unknown"

	// 根据路径确定资源类型
	pathParts := strings.Split(strings.Trim(path, "/"), "/")
	if len(pathParts) >= 2 {
		resource = pathParts[1] // 通常第二个部分是资源类型
	}

	// 根据方法确定操作类型
	switch method {
	case "GET":
		if strings.Contains(path, "/:") || strings.HasSuffix(path, "/detail") {
			action = "VIEW"
		} else {
			action = "LIST"
		}
	case "POST":
		action = "CREATE"
	case "PUT":
		action = "UPDATE"
	case "DELETE":
		action = "DELETE"
	}

	// 特殊处理一些路径
	if strings.Contains(path, "/login") {
		action = "LOGIN"
		resource = "auth"
	} else if strings.Contains(path, "/logout") {
		action = "LOGOUT"
		resource = "auth"
	} else if strings.Contains(path, "/register") {
		action = "REGISTER"
		resource = "auth"
	}

	return action, resource
}

// shouldIgnoreLog 判断是否应该忽略记录某些路径的日志
func shouldIgnoreLog(path string) bool {
	// 忽略静态资源和健康检查等路径
	ignorePaths := []string{
		"/health",
		"/metrics",
		"/favicon.ico",
		"/static/",
		"/assets/",
		"/public/",
	}

	for _, ignorePath := range ignorePaths {
		if strings.Contains(path, ignorePath) {
			return true
		}
	}

	return false
}
